package priv.cwr.springboot.demo.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import priv.cwr.springboot.demo.component.Errors;
import priv.cwr.springboot.demo.configuration.UserCenterGlobal;
import priv.cwr.springboot.demo.exception.ApiException;
import priv.cwr.springboot.demo.mapper.DeptMapper;
import priv.cwr.springboot.demo.mapper.UserMapper;
import priv.cwr.springboot.demo.model.db.UserEntity;
import priv.cwr.springboot.demo.model.vo.UserForm;
import priv.cwr.springboot.demo.model.vo.UserMoveForm;
import priv.cwr.springboot.demo.model.vo.base.PageNumber;
import priv.cwr.springboot.demo.model.vo.base.Result;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * User: R
 * Date: 2018/8/29
 * Time: 11:00
 * Created with IntelliJ IDEA.
 */
@Service
public class UserService {
    private final Errors errors;
    private final UserMapper userMapper;
    private final DeptMapper deptMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final RedisService redisService;
    private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();

    public UserService(Errors errors,
                       UserMapper userMapper,
                       DeptMapper deptMapper,
                       StringRedisTemplate stringRedisTemplate,
                       RedisService redisService) {
        this.errors = errors;
        this.userMapper = userMapper;
        this.deptMapper = deptMapper;
        this.stringRedisTemplate = stringRedisTemplate;
        this.redisService = redisService;
    }

    /**
     * 添加用户
     *
     * @param userEntity 用户实体
     * @return 用户id
     */
    @Transactional
    public long add(UserEntity userEntity) {
        try {
            this.userMapper.insert(userEntity);
            return userEntity.getUserId();
        } catch (Exception e) {
            // 配合Transactional手动让spring回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new ApiException("添加用户失败", new Result(errors, 1001, HttpStatus.INTERNAL_SERVER_ERROR.value(), "添加"));
        }
    }

    /**
     * 修改用户
     *
     * @param userEntity 用户实体
     * @return
     */
    @Transactional
    public boolean update(UserEntity userEntity) {
        try {
            this.userMapper.updateByPrimaryKeySelective(userEntity);
            return true;
        } catch (Exception e) {
            throw new ApiException("修改用户失败", new Result(errors, 1001, HttpStatus.INTERNAL_SERVER_ERROR.value(), "修改"));
        }
    }

    /**
     * 查询员工列表（PC端）
     *
     * @param pageNumber 分页参数
     * @param name       员工姓名（模糊查询）
     * @param phone      电话（全匹配）
     * @param deptId     部门id
     * @return
     */
    public Page<UserForm> findAll(PageNumber pageNumber, String name, String phone, Long deptId) {
        int p = Preconditions.checkNotNull(pageNumber.getPage());
        int r = Preconditions.checkNotNull(pageNumber.getRows());
        //用户名称
        if (name != null && !name.isEmpty()) {
            name = "%" + name + "%";
        } else {
            name = null;
        }
        String depts = null;
        //所属部门
        if (deptId != null) {
            depts = this.deptMapper.findChildDept(deptId);
            depts = depts.substring(1);
        }
        String finalName = name;
        String finalDepts = depts;
        return PageHelper.startPage(p, r).doSelectPage(() -> this.userMapper.findAll(finalName, phone, finalDepts));
    }

    /**
     * 查询员工列表（移动端）
     *
     * @param pageNumber 分页参数
     * @param deptId     部门id
     * @return
     */
    public Page<UserForm> findAllByApp(PageNumber pageNumber, Long deptId) {
        int p = Preconditions.checkNotNull(pageNumber.getPage());
        int r = Preconditions.checkNotNull(pageNumber.getRows());
        //返回给前端的数据
        Page<UserForm> result = new Page<>();
        //list为缓存或者数据库中查询出的数据
        List<UserForm> list = null;
        //redis的key
        String key;
        //查询所有员工
        if (deptId == null) {
            key = UserCenterGlobal.USER_LIST_ALL;
        } else {
            //按部门查询员工
            key = UserCenterGlobal.USER_LIST_DEPTID + deptId;
        }
        //首先查看是否有缓存
        if (this.stringRedisTemplate.hasKey(key)) {
            try {
                list = OBJECTMAPPER.readValue(
                        this.stringRedisTemplate.opsForValue().get(key),
                        new TypeReference<List<UserForm>>() {
                        }
                );
                for (int i = (p - 1) * r; (i < (p - 1) * r + r) && (i < list.size()); i++) {
                    result.add(list.get(i));
                }
                result.setTotal(list.size());
                result.setPages((int) Math.ceil(list.size() / (double) r));
                result.setPageNum(p);
                result.setPageSize(r);
                return result;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //如果缓存没有或者出现异常
        if (list == null) {
            //异步刷新缓存
            this.redisService.writeUserList(key, deptId);
            //从数据库查询需要的数据返回
            return PageHelper.startPage(p, r).doSelectPage(() -> this.userMapper.findAllByApp(deptId));
        }
        return null;
    }

    /**
     * 查询单个用户
     *
     * @param id
     * @return
     */
    public UserEntity findOne(Long id) {
        return this.userMapper.selectByPrimaryKey(id);
    }

    /**
     * 批量移动用户到指定栏目
     *
     * @param userMoveForm
     * @return
     */
    public boolean moveToDept(UserMoveForm userMoveForm) {
        return this.userMapper.move(userMoveForm.getDeptId(), userMoveForm.getUserIds()) > 0;
    }
}
